﻿//-----------------------------------------------------------------------
// <copyright file="MultipleSelectRefinementPanelUserControl.ascx.cs" company="Microsoft Services | Global delivery">
// Copyright (c) Microsoft Services | Global delivery.
// All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <date>15-May-2012</date>
// <summary>This class renders the Multiple Select Refinement Panel.</summary>
//----------------------------------------------------------------------- 

namespace Microsoft.Services.SP.WebParts
{
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Xml;
    using System.Xml.XPath;

    /// <summary>
    /// Multiple Select Refinement Panel User Control
    /// </summary>
    public partial class MultipleSelectRefinementPanelUserControl : UserControl
    {
        /// <summary>
        /// Refiner Xml.
        /// </summary>
        private string refinerXml;

        /// <summary>
        /// Filete Categry Definition.
        /// </summary>
        private string filterCategoryDefinition;

        /// <summary>
        /// Boolean value to set collapsing for unselected categories.
        /// </summary>
        private bool collapseUnselectedCategories = true;

        /// <summary>
        /// Gets or sets the refiner XML.
        /// </summary>
        /// <value>
        /// The refiner XML.
        /// </value>
        public string RefinerXml
        {
            get { return this.refinerXml; }
            set { this.refinerXml = value; }
        }

        /// <summary>
        /// Gets or sets the filter category definition.
        /// </summary>
        /// <value>
        /// The filter category definition.
        /// </value>
        public string FilterCategoryDefinition
        {
            get { return this.filterCategoryDefinition; }
            set { this.filterCategoryDefinition = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether [collapse unselected categories].
        /// </summary>
        /// <value>
        /// <c>true</c> if [collapse unselected categories]; otherwise, <c>false</c>.
        /// </value>
        public bool CollapseUnselectedCategories
        {
            get
            {
                return this.collapseUnselectedCategories;
            }

            set
            {
                this.collapseUnselectedCategories = value;
            }
        }

        /// <summary>
        /// Handles the Load event of the Page control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            XPathNavigator refinerNav = default(XPathNavigator);
            string category = string.Empty, mp = string.Empty, value = string.Empty, tooltip = string.Empty, url = string.Empty, count = string.Empty;
            TreeNode rootNode, childNode = default(TreeNode);

            try
            {
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(this.RefinerXml);
                XPathNavigator xpathNav = xmlDoc.CreateNavigator();

                XmlDocument xmlDef = new XmlDocument();
                xmlDef.LoadXml(this.FilterCategoryDefinition);
                XPathNavigator xpathNavDef = xmlDef.CreateNavigator();
                
                XPathNodeIterator filterPanels = xpathNav.SelectSingleNode("/FilterPanel").SelectChildren(XPathNodeType.Element);

                string absUrl = HttpUtility.UrlDecode(this.Page.Request.Url.AbsoluteUri);

                this.tvRefinerTreeView.Attributes.Add("onclick", "javascript:return treeNodeLinksDisable(event)");

                while (filterPanels.MoveNext())
                {
                    category = filterPanels.Current.GetAttribute("DisplayName", string.Empty);
                    mp = filterPanels.Current.GetAttribute("ManagedProperty", string.Empty);
                    refinerNav = xpathNav.SelectSingleNode("/FilterPanel/FilterCategory[@DisplayName=\"" + category + "\"]/MoreFilters");

                    if (refinerNav == null)
                    {
                        refinerNav = xpathNav.SelectSingleNode("/FilterPanel/FilterCategory[@DisplayName=\"" + category + "\"]/Filters");
                    }

                    if (string.IsNullOrEmpty(mp))
                    {
                        continue;
                    }

                    XPathNavigator customNavCat = xpathNavDef.SelectSingleNode("/FilterCategories/Category[@Title=\"" + category + "\"]/CustomFilters");

                    rootNode = new TreeNode(category, mp);
                    rootNode.Expand();
                    rootNode.NavigateUrl = "##";
                    this.tvRefinerTreeView.Nodes.Add(rootNode);

                    XPathNodeIterator refFilters = refinerNav.Select("./Filter");

                    XPathNodeIterator refFiltersChildren = default(XPathNodeIterator);
                    XPathNavigator customNavRef = default(XPathNavigator);

                    int nodeSelectedCount = 0;

                    while (refFilters.MoveNext())
                    {
                        refFiltersChildren = refFilters.Current.SelectChildren(XPathNodeType.Element);
                        while (refFiltersChildren.MoveNext())
                        {
                            switch (refFiltersChildren.Current.LocalName)
                            {
                                case "Value":
                                    value = refFiltersChildren.Current.Value;
                                    break;
                                case "Tooltip":
                                    tooltip = refFiltersChildren.Current.Value;
                                    break;
                                case "Count":
                                    count = refFiltersChildren.Current.Value;
                                    break;
                                default:
                                    break;
                            }
                        }

                        if (!string.IsNullOrEmpty(value))
                        {
                            childNode = new TreeNode(count != string.Empty ? string.Format("{0} ({1})", value, count) : value);
                            childNode.ToolTip = tooltip;
                            childNode.ShowCheckBox = true;

                            string refinerName = tooltip;
                            string refinerValue = string.Empty, dataType = string.Empty, nodeValue = string.Empty;
                            string op = ":";

                            if (customNavCat != null)
                            {
                                dataType = customNavCat.GetAttribute("DataType", string.Empty);
                                
                                customNavRef = customNavCat.SelectSingleNode("CustomFilter[@CustomValue=\"" + refinerName + "\"]/OriginalValue");

                                if (customNavRef != null)
                                {
                                    nodeValue = customNavRef.Value;
                                }

                                if (dataType.Equals("date", StringComparison.InvariantCultureIgnoreCase))
                                {
                                    string[] values = nodeValue.Split(new string[] { ".." }, StringSplitOptions.None);

                                    int num;
                                    if (values.Length > 1)
                                    {
                                        for (int i = 0; i < values.Length; i++)
                                        {
                                            Int32.TryParse(values[i], out num);
                                            if (i == 0 && num == 0)
                                            {
                                                values[i] = "1000/01/01";
                                            }
                                            else if (i == 1 && num == 0)
                                            {
                                                values[i] = "9999/01/01";
                                            }
                                            else
                                            {
                                                values[i] = DateTime.Now.AddDays(num).ToString("yyyy/MM/dd");
                                            }
                                        }

                                        refinerName = string.Join("..", values);
                                    }
                                }
                                else
                                {
                                    refinerName = nodeValue;
                                }
                            }

                            bool whiteSpace = Regex.IsMatch(refinerName, @"[\s]", RegexOptions.IgnoreCase);
                            refinerValue = string.Format(whiteSpace == true ? "{0}{1}\"{2}\"" : "{0}{1}{2}", mp, op, refinerName);
                            childNode.Value = refinerValue;

                            if (absUrl.Contains(refinerValue))
                            {
                                childNode.Checked = true;
                                nodeSelectedCount++;
                            }
                            
                            if (count != string.Empty)
                            {
                                childNode.NavigateUrl = "#";
                            }
                            else
                            {
                                childNode.NavigateUrl = "##";
                            }

                            rootNode.ChildNodes.Add(childNode);
                        }
                    }

                    if (nodeSelectedCount == 0 && rootNode.ChildNodes[0].Text.StartsWith("Any", StringComparison.InvariantCultureIgnoreCase))
                    {
                        rootNode.ChildNodes[0].Checked = true;

                        if (this.CollapseUnselectedCategories)
                        {
                            rootNode.Collapse();
                        }
                    }

                    nodeSelectedCount = 0;
                }

                if (this.tvRefinerTreeView.Nodes.Count > 0)
                {
                    string script = @"$(""#" + this.tvRefinerTreeView.ClientID + @" input[type='checkbox']"").bind('click',
                                    function()
                                    { 
                                        var isChecked = this.checked; 
                                        var tables = $(this).parents('div:first').children('table'); 
                                        var checkboxes = tables.find(':checkbox'); 
                                        var checkboxesUnchecked = tables.find(':checkbox:not(:checked)'); 
                                        if(isChecked)
                                        {
                                            if(this.title.indexOf('Any') == 0)
                                            {
                                                checkboxes.attr('checked', !isChecked); 
                                                this.checked = isChecked;
                                            }
                                            else if($(checkboxes.get(0)).attr('title').indexOf('Any') == 0)
                                            {
                                                checkboxes.get(0).checked = !isChecked;
                                            }   
                                        }
                                        else if(checkboxes.length == checkboxesUnchecked.length)
                                        {
                                            if($(checkboxes.get(0)).attr('title').indexOf('Any') == 0)
                                            {
                                                checkboxes.get(0).checked = !isChecked;
                                            }
                                        }
                                    }); function treeNodeLinksDisable(event)
                                        {
                                            var obj;
                                            // Internet Explorer
                                            if (event.srcElement)
                                            {
                                                obj = event.srcElement;
                                            }
                                            // Netscape and Firefox
                                            else if (event.target)
                                            {
                                                obj = event.target;
                                            }
                                            if(obj.tagName == 'A' || obj.tagName == 'a')
                                            {
                                                return false;
                                            }
                                        }";

                    //// Code to disable all the anchor tags under the TreeView control
                    //// $(document).ready(function() {
                    ////    $(""#" + this.tvRefinerTreeView.ClientID + @" a"").click(function(e) {
                    ////       e.preventDefault();
                    ////    });
                    ////});";

                    if (!this.Page.ClientScript.IsStartupScriptRegistered(this.ID + "MultiSelectRefiner"))
                    {
                        this.Page.ClientScript.RegisterStartupScript(this.GetType(), this.ID + "MultiSelectRefiner", script, true);
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                if (this.tvRefinerTreeView.Nodes.Count == 0)
                {
                    string message = refinerNav.SelectSingleNode("./Filter/Value").ToString(); ////"No refiners available";
                    rootNode = new TreeNode(message);
                    rootNode.SelectAction = TreeNodeSelectAction.None;
                    this.tvRefinerTreeView.Nodes.Add(rootNode);
                    this.btnRefinerApply.Visible = false;
                }
            }
        }

        /// <summary>
        /// Handles the Click event of the btnRefinerApply control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected void BtnRefinerApply_Click(object sender, EventArgs e)
        {
            try
            {
                string pageUrlWithoutQueryString = this.Page.Request.Url.GetLeftPart(UriPartial.Path);
                NameValueCollection queryParams = HttpUtility.ParseQueryString(this.Page.Request.Url.Query);
                
                //// Pickup the queryText that the user types in
                string query = queryParams.Get("k");
                string additonalFilters = queryParams.Get("a");
                string refinerFilters = queryParams.Get("r");

                TreeNodeCollection collec = this.tvRefinerTreeView.CheckedNodes;
                List<string> str = new List<string>();
                string mp = string.Empty, refinerName = string.Empty, refiner = string.Empty;

                Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>();
                
                foreach (TreeNode node in collec)
                {
                    if (node.NavigateUrl == "#")
                    {
                        mp = node.Parent.Value;
                        refinerName = node.ToolTip;
                        refiner = node.Value;

                        if (dict.ContainsKey(mp))
                        {
                            List<string> list = dict[mp];
                            list.Add(refiner);
                        }
                        else
                        {
                            List<string> list = new List<string>();
                            list.Add(refiner);
                            dict.Add(mp, list);
                        }
                    }
                }

                StringBuilder sb = new StringBuilder();
                foreach (KeyValuePair<string, List<string>> keyValue in dict)
                {
                    sb.Append("(");
                    List<string> list = keyValue.Value;
                    sb.Append(string.Join(" OR ", list.ToArray()));
                    sb.Append(") AND ");
                }

                string newAdditonalQuery = string.Empty;
                if (sb.ToString().Length > 0)
                {
                    newAdditonalQuery = sb.ToString().Remove(sb.ToString().Length - 5);
                }

                string queryString = string.Format("{0}?k={1}&a={2}", pageUrlWithoutQueryString, query, newAdditonalQuery);
                this.Page.Response.Redirect(queryString);
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}
